/**  
 * Copyright (c) 2008, Noel Lynch All rights reserved. Redistribution and use  
 * in source and binary forms, with or without modification, are permitted  
 * provided that the following conditions are met: Redistributions of source  
 * code must retain the above copyright notice, this list of conditions and the  
 * following disclaimer. Redistributions in binary form must reproduce the above  
 * copyright notice, this list of conditions and the following disclaimer in the  
 * documentation and/or other materials provided with the distribution. Neither  
 * the name of Noel Lynch nor the names of contributors may be used to  
 * endorse or promote products derived from this software without specific prior  
 * written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT  
 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A  
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR  
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,  
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;  
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF  
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
 */
// Jul 24, 2008

package com.sceneworker.editors.textureunitseditor;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.concurrent.Callable;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.tree.TreePath;

import net.miginfocom.swing.MigLayout;

import com.acarter.scenemonitor.SceneMonitor;
import com.jme.image.Texture;
import com.jme.image.Texture.WrapAxis;
import com.jme.scene.Geometry;
import com.jme.scene.state.TextureState;
import com.jme.util.GameTaskQueueManager;
import com.jme.util.TextureManager;
import com.jme2utils.staticutils.TextureUtils;
import com.myjavautils.GenericUtils;
import com.myjavautils.swing.MigLayoutUtils;
import com.myjavautils.swing.SwingComponentFactory;
import com.sceneworker.app.globals.SceneWorkerGlobals;

public class TextureUnitsEditorPanel extends JPanel implements ActionListener {

	private static final int IMAGE_DRAW_WIDTH = 100;
	private static final int IMAGE_DRAW_HEIGHT = 100;
	private static final int IMAGE_X_START = 35;

	private		JButton									mcl_done;
	private		JButton									mcl_loadNew;
	private		JButton									mcl_delete;
	private		JCheckBox								mcl_keepSettings;
	private		JCheckBox								mcl_keepCoords;
	private		JDialog									mcl_par;
	private		TextureState							mcl_texureState;
	private		ArrayList<TextureDrawStruct>			mcla_textureImages = new ArrayList<TextureDrawStruct>();
	private		int										mi_texureDrawStructSelected = -1;
	private		JPanel									mcl_textureDrawPanel;
	private		JScrollPane								mcl_textureDrawPanelScroller;

	public	TextureUnitsEditorPanel(JDialog cl_par, TextureState cl_texureState) {
		mcl_par = cl_par;
		mcl_texureState = cl_texureState;
		buildPanel();
		
		setMinimumSize(new Dimension(300, 400));
	}

	private	void	buildPanel() {

		this.setLayout(new MigLayout("inset 5"));

		mcl_done = SwingComponentFactory.makeAButton("Done");
		mcl_done.addActionListener(new ActionListener() {
			public	void	actionPerformed(ActionEvent cl_e) {
				mcl_par.dispose();
			}
		});
		
		mcl_loadNew = SwingComponentFactory.makeAButton("Add To Texture Units");
		mcl_loadNew.addActionListener(this);
		
		mcl_delete = SwingComponentFactory.makeAButton("Delete");
		final	TextureUnitsEditorPanel		lcl_this = this;

		mcl_delete.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent cl_e) {
				if(mi_texureDrawStructSelected == -1) { return; }

				TextureDrawStruct		lcl_struct = mcla_textureImages.get(mi_texureDrawStructSelected);
				final	int				li_textureUnitToDelete = lcl_struct.mi_textureUnit;

				mcla_textureImages.remove(lcl_struct);
				mi_texureDrawStructSelected = -1;

				GameTaskQueueManager.getManager().update(new Callable<Object>() {
					public Object call() throws Exception {
						Texture				lcl_texture = mcl_texureState.getTexture(li_textureUnitToDelete);
						
						//lcl_ts.deleteAll();
						mcl_texureState.removeTexture(li_textureUnitToDelete);
						mcl_texureState.setNeedsRefresh(true);
						lcl_this.populateTextureDrawStructArray(mcl_texureState);
						lcl_this.repaint();

						return null;
					}
				});
			}
		});

		buildTextureImages(mcl_texureState);

		mcl_keepSettings = SwingComponentFactory.makeACheckBox("When replacing keep original texture settings", true);
		add(mcl_keepSettings, "wrap");
		mcl_keepCoords = SwingComponentFactory.makeACheckBox("When loading new texture copy last texture's texture coordinates", true);
		add(mcl_keepCoords, "wrap");
		
		MigLayoutUtils.makeRightAlignedButtonBar(this, mcl_done, mcl_loadNew, mcl_delete);
		
	}

	class	TextureDrawStruct {
		public	BufferedImage		mcl_im;
		public	int					mi_textureUnit;
		public	String				mstr_name;
		public	boolean				mb_empty;
	}

	private		void	populateTextureDrawStructArray(TextureState cl_state) {
		mcla_textureImages.clear();
		int			li_numUnits = cl_state.getNumberOfSetTextures();

		for(int li_index = 0; li_index < li_numUnits; li_index++) {
			Texture		lcl_texture = cl_state.getTexture(li_index);

			TextureDrawStruct		lcl_struct = new TextureDrawStruct();
			lcl_struct.mi_textureUnit = li_index;

			if(lcl_texture != null) {
				try {
					if(lcl_texture.getImage() != null) {
						//ImageIO.read(new URL(lcl_texture.getImageLocation()));
						lcl_struct.mcl_im = TextureUtils.createBufferedImageFromTexture(lcl_texture, null, true);
					}
					if(lcl_texture.getImageLocation() != null) {
						lcl_struct.mstr_name = lcl_texture.getImageLocation().substring(lcl_texture.getImageLocation().lastIndexOf(File.separatorChar) + 1);
					} else {
						lcl_struct.mstr_name = "Unknown";
					}
					

				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} else {
				lcl_struct.mb_empty = true;
			}

			mcla_textureImages.add(lcl_struct);
		}
	}

	protected	void	buildTextureImages(final TextureState cl_state) {
		GameTaskQueueManager.getManager().update(new Callable<Void>() {
			public Void call() throws Exception {
				populateTextureDrawStructArray(cl_state);
				return null;
			}
		});
		
		mcl_textureDrawPanel = new JPanel() {
			
			@Override
			public Dimension getMinimumSize() {
				return new Dimension(300, 300);
			}

			@Override
			protected void paintComponent(Graphics cl_g) {
				cl_g.clearRect(0, 0, getWidth(), getHeight());
				int	li_y = 0;

				TextureDrawStruct		lcl_selected = null;
				if(mi_texureDrawStructSelected != -1) {
					lcl_selected = mcla_textureImages.get(mi_texureDrawStructSelected);
				}

				for(TextureDrawStruct lcl_tDraw : mcla_textureImages) {
					if(lcl_selected != null) {
						if(lcl_selected.equals(lcl_tDraw)) {
							cl_g.setColor(Color.green);
							cl_g.fillRect(0, li_y, getWidth(), IMAGE_DRAW_HEIGHT);
						}
					}

					cl_g.setColor(Color.BLACK);
					cl_g.drawString("TU " + lcl_tDraw.mi_textureUnit, 0, li_y + 10);

					if(lcl_tDraw.mcl_im == null) {
						if(lcl_tDraw.mb_empty) {
							cl_g.drawString("Unit Empty", IMAGE_X_START, li_y + 10);
						} else {
							cl_g.drawString("Cannot draw texture", IMAGE_X_START, li_y + 10);
						}

					} else {
						cl_g.drawImage(lcl_tDraw.mcl_im, IMAGE_X_START, li_y, IMAGE_DRAW_WIDTH, IMAGE_DRAW_HEIGHT, this);
						cl_g.drawString(lcl_tDraw.mstr_name, IMAGE_X_START + IMAGE_DRAW_WIDTH + 5, li_y + 10);
						cl_g.drawString("" + lcl_tDraw.mcl_im.getWidth() + " x " + lcl_tDraw.mcl_im.getWidth(), IMAGE_X_START + IMAGE_DRAW_WIDTH + 5, li_y + 30);
					}

					li_y += IMAGE_DRAW_WIDTH + 5;
				}
			}
		};
		
		mcl_textureDrawPanel.addMouseListener(new MouseListener() {

			public void mouseClicked(MouseEvent cl_e) {
				for(int li_y = 0, li_cnt = 0; li_y < mcl_textureDrawPanel.getHeight(); li_y += (IMAGE_DRAW_HEIGHT + 5), li_cnt++) {
					if((cl_e.getY() > li_y) && (cl_e.getY() < (li_y + IMAGE_DRAW_HEIGHT))) {
						if(li_cnt < mcla_textureImages.size()) {
							mi_texureDrawStructSelected = li_cnt;
							mcl_loadNew.setText("Load New Into Unit " + mcla_textureImages.get(mi_texureDrawStructSelected).mi_textureUnit);
						} else {
							mi_texureDrawStructSelected = -1;
							mcl_loadNew.setText("Add To Texture Units");
						}
						repaint();
						return;
					}
				}

				mi_texureDrawStructSelected = -1;
			}

			public void mouseEntered(MouseEvent e) {
			}

			public void mouseExited(MouseEvent e) {
			}

			public void mousePressed(MouseEvent e) {
			}

			public void mouseReleased(MouseEvent e) {
			}

		});

		mcl_textureDrawPanelScroller = new JScrollPane();
		mcl_textureDrawPanelScroller.setViewportView(mcl_textureDrawPanel);
		mcl_textureDrawPanelScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
		mcl_textureDrawPanelScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
		mcl_textureDrawPanelScroller.revalidate();
		mcl_textureDrawPanelScroller.setMinimumSize(new Dimension(300, 300));
		add(mcl_textureDrawPanelScroller, "width 100%, height 100%, wrap");
	}


	public void actionPerformed(ActionEvent cl_e) {
		if(cl_e.getSource() == mcl_loadNew) {
			File	lcl_f = GenericUtils.getAnImageFile(this);

			if(lcl_f == null) { return; }
			
			try {
				Texture		lcl_texture = TextureManager.loadTexture(lcl_f.toURL(), Texture.MinificationFilter.Trilinear, 
						Texture.MagnificationFilter.Bilinear);

				final	TextureState		lcl_ts = mcl_texureState;
				if(mi_texureDrawStructSelected == -1) {
					lcl_ts.setTexture(lcl_texture, lcl_ts.getNumberOfSetTextures());

					if(mcl_keepCoords.isSelected()) {
						TreePath		lcl_objPath = SceneMonitor.getMonitor().getMonitorTree().getSelectionPath();

						// get the parent
						TreePath	lcl_parPath = lcl_objPath.getParentPath();
						Object		lcl_parObj = null;

						if(lcl_parPath != null) {
							lcl_parObj = lcl_parPath.getLastPathComponent();
						}

						if(lcl_parObj != null) {
							if(lcl_parObj instanceof Geometry) {
								((Geometry)lcl_parObj).copyTextureCoordinates(0, lcl_ts.getNumberOfSetTextures() - 1, 1);
							}
						}

					}

					GameTaskQueueManager.getManager().update(new Callable<Void>() {
						public Void call() throws Exception {
							populateTextureDrawStructArray(lcl_ts);
							repaint();
							return null;
						}
					});
					

				} else {
					int		li_tu = mcla_textureImages.get(mi_texureDrawStructSelected).mi_textureUnit;

					if(mcla_textureImages.get(mi_texureDrawStructSelected).mb_empty) {
						lcl_ts.setTexture(lcl_texture, li_tu);
					} else {
						if(mcl_keepSettings.isSelected()) {
							copyInTexture(lcl_ts, li_tu, lcl_texture);
						} else {
							lcl_ts.setTexture(lcl_texture, li_tu);
						}

					}

					GameTaskQueueManager.getManager().update(new Callable<Void>() {
						public Void call() throws Exception {
							populateTextureDrawStructArray(lcl_ts);
							repaint();
							return null;
						}
					});
					
				}

				lcl_ts.setNeedsRefresh(true);
				mcl_textureDrawPanelScroller.getViewport().getView().setMinimumSize(new Dimension(300, mcla_textureImages.size() * (IMAGE_DRAW_HEIGHT + 5)));
				mcl_textureDrawPanelScroller.revalidate();
			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			repaint();
		}
	}

	private	void	copyInTexture(TextureState cl_ts, int i_oldUnit, Texture cl_newTexture) {
		Texture		lcl_oldTexture = cl_ts.getTexture(i_oldUnit);

		cl_newTexture.setApply(lcl_oldTexture.getApply());
		cl_newTexture.setBlendColor(lcl_oldTexture.getBlendColor());
		cl_newTexture.setCombineFuncAlpha(lcl_oldTexture.getCombineFuncAlpha());
		cl_newTexture.setCombineFuncRGB(lcl_oldTexture.getCombineFuncRGB());
		cl_newTexture.setCombineOp0Alpha(lcl_oldTexture.getCombineOp0Alpha());
		cl_newTexture.setCombineOp0RGB(lcl_oldTexture.getCombineOp0RGB());
		cl_newTexture.setCombineOp1Alpha(lcl_oldTexture.getCombineOp1Alpha());
		cl_newTexture.setCombineOp1RGB(lcl_oldTexture.getCombineOp1RGB());
		cl_newTexture.setCombineOp2Alpha(lcl_oldTexture.getCombineOp2Alpha());
		cl_newTexture.setCombineOp2RGB(lcl_oldTexture.getCombineOp2RGB());

		cl_newTexture.setCombineScaleAlpha(lcl_oldTexture.getCombineScaleAlpha());
		cl_newTexture.setCombineScaleRGB(lcl_oldTexture.getCombineScaleRGB());

		cl_newTexture.setCombineSrc0Alpha(lcl_oldTexture.getCombineSrc0Alpha());
		cl_newTexture.setCombineSrc0RGB(lcl_oldTexture.getCombineSrc0RGB());
		cl_newTexture.setCombineSrc1Alpha(lcl_oldTexture.getCombineSrc1Alpha());
		cl_newTexture.setCombineSrc1RGB(lcl_oldTexture.getCombineSrc1RGB());
		cl_newTexture.setCombineSrc2Alpha(lcl_oldTexture.getCombineSrc2Alpha());
		cl_newTexture.setCombineSrc2RGB(lcl_oldTexture.getCombineSrc2RGB());

		cl_newTexture.setAnisotropicFilterPercent(lcl_oldTexture.getAnisotropicFilterPercent());
		cl_newTexture.setEnvironmentalMapMode(lcl_oldTexture.getEnvironmentalMapMode());
		cl_newTexture.setMagnificationFilter(lcl_oldTexture.getMagnificationFilter());
		cl_newTexture.setMinificationFilter(lcl_oldTexture.getMinificationFilter());
		cl_newTexture.setRotation(lcl_oldTexture.getRotation());
		cl_newTexture.setScale(lcl_oldTexture.getScale());
		cl_newTexture.setTranslation(lcl_oldTexture.getTranslation());
		cl_newTexture.setWrap(WrapAxis.S, lcl_oldTexture.getWrap(WrapAxis.S));
		cl_newTexture.setWrap(WrapAxis.T, lcl_oldTexture.getWrap(WrapAxis.T));

		cl_ts.setTexture(cl_newTexture, i_oldUnit);
	}


}
